home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 6366 / 6366.xpi / components / xdGestureHandler.js < prev    next >
Text File  |  2009-11-17  |  17KB  |  536 lines

  1.  
  2. const Cc = Components.classes;
  3. const Ci = Components.interfaces;
  4. const Cr = Components.results;
  5.  
  6. const PREFS_DOMAIN = "extensions.firegestures.";
  7. const HTML_NS = "http://www.w3.org/1999/xhtml";
  8.  
  9. const STATE_READY    = 0;
  10. const STATE_GESTURE  = 1;
  11. const STATE_ROCKER   = 2;
  12. const STATE_WHEEL    = 3;
  13. const STATE_KEYPRESS = 4;
  14.  
  15. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22. function xdGestureHandler() {}
  23.  
  24.  
  25. xdGestureHandler.prototype = {
  26.  
  27.  
  28.     classDescription: "Mouse Gesture Handler",
  29.     contractID: "@xuldev.org/firegestures/handler;1",
  30.     classID: Components.ID("{ca559550-8ab4-41c5-a72f-fd931322cc7e}"),
  31.     QueryInterface: XPCOMUtils.generateQI([
  32.         Ci.nsISupports,
  33.         Ci.nsIObserver,
  34.         Ci.nsISupportsWeakReference,
  35.         Ci.nsIDOMEventListener,
  36.         Ci.nsITimerCallback,
  37.         Ci.xdIGestureHandler
  38.     ]),
  39.  
  40.  
  41.  
  42.     sourceNode: null,
  43.  
  44.  
  45.  
  46.     _drawArea: null,
  47.     _lastX: null,
  48.     _lastY: null,
  49.     _directionChain: "",
  50.  
  51.     _gestureObserver: null,
  52.  
  53.  
  54.  
  55.     attach: function FGH_attach(aDrawArea, aObserver) {
  56.         this._drawArea = aDrawArea;
  57.         this._gestureObserver = aObserver;
  58.         this._drawArea.addEventListener("mousedown", this, true);
  59.         this._drawArea.addEventListener("mousemove", this, true);
  60.         this._drawArea.addEventListener("mouseup", this, true);
  61.         this._drawArea.addEventListener("contextmenu", this, true);
  62.         this._drawArea.addEventListener("draggesture", this, true);
  63.         this._reloadPrefs();
  64.         var prefBranch2 = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  65.         prefBranch2.addObserver(PREFS_DOMAIN, this, true);
  66.     },
  67.  
  68.     detach: function FGH_detach() {
  69.         this._drawArea.removeEventListener("mousedown", this, true);
  70.         this._drawArea.removeEventListener("mousemove", this, true);
  71.         this._drawArea.removeEventListener("mouseup", this, true);
  72.         this._drawArea.removeEventListener("contextmenu", this, true);
  73.         this._drawArea.removeEventListener("draggesture", this, true);
  74.         var prefBranch2 = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  75.         prefBranch2.removeObserver(PREFS_DOMAIN, this);
  76.         this._clearTimeout();
  77.         this.sourceNode = null;
  78.         this._drawArea = null;
  79.         this._gestureObserver = null;
  80.         this._prefs = null;
  81.     },
  82.  
  83.     _reloadPrefs: function FGH__reloadPrefs() {
  84.         var prefBranch = Cc["@mozilla.org/preferences-service;1"]
  85.                          .getService(Ci.nsIPrefService)
  86.                          .getBranch(PREFS_DOMAIN);
  87.         var getPref = function(aName) {
  88.             try {
  89.                 switch (prefBranch.getPrefType(aName)) {
  90.                     case prefBranch.PREF_STRING:
  91.                         return prefBranch.getCharPref(aName);
  92.                     case prefBranch.PREF_BOOL:
  93.                         return prefBranch.getBoolPref(aName);
  94.                     case prefBranch.PREF_INT:
  95.                         return prefBranch.getIntPref(aName);
  96.                     default:
  97.                         throw null;
  98.                 }
  99.             }
  100.             catch(ex) {
  101.             }
  102.         };
  103.         this._triggerButton  = getPref("trigger_button");
  104.         this._suppressAlt    = getPref("suppress.alt");
  105.         this._trailEnabled   = getPref("mousetrail");
  106.         this._trailSize      = getPref("mousetrail.size");
  107.         this._trailColor     = getPref("mousetrail.color");
  108.         this._gestureTimeout = getPref("gesture_timeout");
  109.         this._mouseGestureEnabled    = getPref("mousegesture");
  110.         this._wheelGestureEnabled    = getPref("wheelgesture");
  111.         this._rockerGestureEnabled   = getPref("rockergesture");
  112.         this._keypressGestureEnabled = getPref("keypressgesture");
  113.         this._drawArea.removeEventListener("DOMMouseScroll", this, true);
  114.         this._drawArea.removeEventListener("click", this, true);
  115.         if (this._wheelGestureEnabled)
  116.             this._drawArea.addEventListener("DOMMouseScroll", this, true);
  117.         if (this._rockerGestureEnabled)
  118.             this._drawArea.addEventListener("click", this, true);
  119.         var tabbrowser = this._drawArea.ownerDocument.getBindingParent(this._drawArea);
  120.         if (tabbrowser && tabbrowser.localName == "tabbrowser") {
  121.             tabbrowser.mStrip.removeEventListener("DOMMouseScroll", this._wheelOnTabBar, true);
  122.             if (getPref("tabwheelgesture"))
  123.                 tabbrowser.mStrip.addEventListener("DOMMouseScroll", this._wheelOnTabBar, true);
  124.         }
  125.         if (this._triggerButton == 1) {
  126.             var prefSvc = Cc["@mozilla.org/preferences-service;1"]
  127.                           .getService(Ci.nsIPrefBranch2)
  128.                           .QueryInterface(Ci.nsIPrefService);
  129.             prefSvc.setBoolPref("middlemouse.contentLoadURL", false);
  130.         }
  131.     },
  132.  
  133.  
  134.  
  135.     _state: STATE_READY,
  136.     _isMouseDownL: false,
  137.     _isMouseDownM: false,
  138.     _isMouseDownR: false,
  139.     _suppressContext: false,
  140.     _shouldFireContext: false,
  141.  
  142.     handleEvent: function FGH_handleEvent(event) {
  143.         switch (event.type) {
  144.             case "mousedown": 
  145.                 if (event.button == 0) {
  146.                     var targetName = event.target.localName.toUpperCase();
  147.                     if (targetName == "INPUT" || targetName == "TEXTAREA") {
  148.                         break;
  149.                     }
  150.                     targetName = event.originalTarget.localName;
  151.                     if (targetName == "scrollbarbutton" || targetName == "slider" || targetName == "thumb") {
  152.                         break;
  153.                     }
  154.                     this._isMouseDownL = true;
  155.                     this._isMouseDownM = false;
  156.                     if (this._triggerButton == 0 && !this._isMouseDownM && !this._isMouseDownR && !this._altKey(event)) {
  157.                         this._state = STATE_GESTURE;
  158.                         this._startGesture(event);
  159.                         if (this._mouseGestureEnabled)
  160.                             event.preventDefault();
  161.                     }
  162.                     else if (this._rockerGestureEnabled && this._isMouseDownR) {
  163.                         this._state = STATE_ROCKER;
  164.                         this._invokeExtraGesture(event, "rocker-left");
  165.                     }
  166.                 }
  167.                 else if (event.button == 1) {
  168.                     this._isMouseDownM = true;
  169.                     if (this._triggerButton == 1 && !this._isMouseDownL && !this._isMouseDownR && !this._altKey(event)) {
  170.                         this._state = STATE_GESTURE;
  171.                         this._startGesture(event);
  172.                         event.stopPropagation();
  173.                     }
  174.                 }
  175.                 else if (event.button == 2) {
  176.                     var targetName = event.target.localName.toUpperCase();
  177.                     if (targetName == "OBJECT" || targetName == "EMBED") {
  178.                         break;
  179.                     }
  180.                     this._isMouseDownR = true;
  181.                     this._isMouseDownM = false;
  182.                     this._suppressContext = false;
  183.                     if (this._triggerButton == 2 && !this._isMouseDownL && !this._isMouseDownM && !this._altKey(event)) {
  184.                         this._state = STATE_GESTURE;
  185.                         this._startGesture(event);
  186.                     }
  187.                     else if (this._rockerGestureEnabled && this._isMouseDownL) {
  188.                         this._state = STATE_ROCKER;
  189.                         this._invokeExtraGesture(event, "rocker-right");
  190.                     }
  191.                 }
  192.                 break;
  193.             case "mousemove": 
  194.                 if (this._state == STATE_GESTURE || this._state == STATE_KEYPRESS) {
  195.                     if (this._mouseGestureEnabled) {
  196.                         if (this._keypressGestureEnabled && (event.ctrlKey || event.shiftKey)) {
  197.                             var type = this._state == STATE_GESTURE ? "keypress-start" : "keypress-progress";
  198.                             this._state = STATE_KEYPRESS;
  199.                             this._invokeExtraGesture(event, type);
  200.                         }
  201.                         this._progressGesture(event);
  202.                     }
  203.                 }
  204.                 else if (this._state == STATE_WHEEL || this._state == STATE_ROCKER) {
  205.                     this._lastX = event.screenX;
  206.                     this._lastY = event.screenY;
  207.                     if (Math.abs(this._lastX - this._lastExtraX) > 10 || 
  208.                         Math.abs(this._lastY - this._lastExtraY) > 10) {
  209.                         this._stopGesture();
  210.                     }
  211.                 }
  212.                 break;
  213.             case "mouseup": 
  214.                 if (event.button == 0)
  215.                     this._isMouseDownL = false;
  216.                 else if (event.button == 1)
  217.                     this._isMouseDownM = false;
  218.                 else if (event.button == 2)
  219.                     this._isMouseDownR = false;
  220.                 if (!this._isMouseDownL && !this._isMouseDownM && !this._isMouseDownR) {
  221.                     if (this._state == STATE_KEYPRESS) {
  222.                         this._state = STATE_READY;
  223.                         if (event.ctrlKey)
  224.                             this._invokeExtraGesture(event, "keypress-ctrl");
  225.                         else if (event.shiftKey)
  226.                             this._invokeExtraGesture(event, "keypress-shift");
  227.                         this._invokeExtraGesture(event, "keypress-stop");
  228.                     }
  229.                     this._stopGesture(event);
  230.                     if (this._shouldFireContext) {
  231.                         this._shouldFireContext = false;
  232.                         this._displayContextMenu(event);
  233.                     }
  234.                 }
  235.                 break;
  236.             case "contextmenu": 
  237.                 if (!this._isMouseDownL && this._isMouseDownR) {
  238.                     this._suppressContext = true;
  239.                     this._shouldFireContext = true;
  240.                 }
  241.                 if (this._suppressContext) {
  242.                     this._suppressContext = false;
  243.                     event.preventDefault();
  244.                     event.stopPropagation();
  245.                 }
  246.                 break;
  247.             case "DOMMouseScroll": 
  248.                 if (this._state == STATE_GESTURE || this._state == STATE_WHEEL) {
  249.                     this._state = STATE_WHEEL;
  250.                     this._invokeExtraGesture(event, event.detail < 0 ? "wheel-up" : "wheel-down");
  251.                     event.preventDefault();
  252.                     event.stopPropagation();
  253.                 }
  254.                 break;
  255.             case "click": 
  256.                 if (this._state == STATE_ROCKER) {
  257.                     event.preventDefault();
  258.                     event.stopPropagation();
  259.                 }
  260.                 break;
  261.             case "draggesture": 
  262.                 if (this._state != STATE_ROCKER)
  263.                     this._isMouseDownL = false;
  264.                 break;
  265.         }
  266.     },
  267.  
  268.     _altKey: function(event) {
  269.         return this._suppressAlt ? event.altKey : false;
  270.     },
  271.  
  272.     _displayContextMenu: function FGH__displayContextMenu(event) {
  273.         with (this._drawArea.ownerDocument.defaultView) {
  274.             if (!nsContextMenu.prototype._setTargetInternal) {
  275.                 nsContextMenu.prototype._setTargetInternal = nsContextMenu.prototype.setTarget;
  276.                 nsContextMenu.prototype.setTarget = function(aNode, aRangeParent, aRangeOffset) {
  277.                     this._setTargetInternal(aNode, aRangeParent, this._rangeOffset);
  278.                 };
  279.             }
  280.             nsContextMenu.prototype._rangeOffset = event.rangeOffset;
  281.         }
  282.         var evt = event.originalTarget.ownerDocument.createEvent("MouseEvents");
  283.         evt.initMouseEvent(
  284.             "contextmenu", true, true, event.originalTarget.ownerDocument.defaultView, 0,
  285.             event.screenX, event.screenY, event.clientX, event.clientY,
  286.             false, false, false, false, 2, null
  287.         );
  288.         event = new XPCNativeWrapper(event);
  289.         event.originalTarget.dispatchEvent(evt);
  290.     },
  291.  
  292.     _wheelOnTabBar: function FGH__wheelOnTabBar(event) {
  293.         var tabbar = null;
  294.         if (event.target.localName == "tab")
  295.             tabbar = event.target.parentNode;
  296.         else if (event.target.localName == "tabs" && event.originalTarget.localName != "menuitem")
  297.             tabbar = event.target;
  298.         else
  299.             return;
  300.         event.preventDefault();
  301.         event.stopPropagation();
  302.         tabbar.advanceSelectedTab(event.detail < 0 ? -1 : 1, true);
  303.     },
  304.  
  305.     _startGesture: function FGH__startGesture(event) {
  306.         this.sourceNode = event.target;
  307.         this._lastX = event.screenX;
  308.         this._lastY = event.screenY;
  309.         this._directionChain = "";
  310.         this._shouldFireContext = false;
  311.         if (this._trailEnabled)
  312.             this.createTrail(event);
  313.     },
  314.  
  315.     _progressGesture: function FGH__progressGesture(event) {
  316.         var x = event.screenX;
  317.         var y = event.screenY;
  318.         var dx = Math.abs(x - this._lastX);
  319.         var dy = Math.abs(y - this._lastY);
  320.         if (dx < 10 && dy < 10)
  321.             return;
  322.         var direction;
  323.         if (dx > dy)
  324.             direction = x < this._lastX ? "L" : "R";
  325.         else
  326.             direction = y < this._lastY ? "U" : "D";
  327.         if (this._trailEnabled)
  328.             this.drawTrail(this._lastX, this._lastY, x, y);
  329.         this._lastX = x;
  330.         this._lastY = y;
  331.         if (this._state == STATE_KEYPRESS)
  332.             return;
  333.         var lastDirection = this._directionChain.charAt(this._directionChain.length - 1);
  334.         if (direction != lastDirection) {
  335.             this._directionChain += direction;
  336.             this._gestureObserver.onDirectionChanged(event, this._directionChain);
  337.         }
  338.         if (this._gestureTimeout > 0)
  339.             this._setTimeout(this._gestureTimeout);
  340.     },
  341.  
  342.     _invokeExtraGesture: function FGH__invokeExtraGesture(event, aGestureType) {
  343.         if (this._state == STATE_WHEEL || this._state == STATE_ROCKER) {
  344.             this._lastExtraX = event.screenX;
  345.             this._lastExtraY = event.screenY;
  346.         }
  347.         if (this._state != STATE_KEYPRESS && this._trailEnabled)
  348.             this.eraseTrail();
  349.         this._gestureObserver.onExtraGesture(event, aGestureType);
  350.         this._suppressContext = true;
  351.         this._shouldFireContext = false;
  352.         this._directionChain = "";
  353.         if (this._state == STATE_WHEEL || this._state == STATE_ROCKER) {
  354.             if (this._gestureTimeout > 0)
  355.                 this._setTimeout(this._gestureTimeout);
  356.         }
  357.     },
  358.  
  359.     _stopGesture: function FGH__stopGesture(event) {
  360.         this._state = STATE_READY;
  361.         this._isMouseDownL = false;
  362.         this._isMouseDownM = false;
  363.         this._isMouseDownR = false;
  364.         if (this._trailEnabled)
  365.             this.eraseTrail();
  366.         if (this._directionChain) {
  367.             this._gestureObserver.onMouseGesture(event, this._directionChain);
  368.             this._suppressContext = true;
  369.             this._shouldFireContext = false;
  370.         }
  371.         this.sourceNode = null;
  372.         this._directionChain = "";
  373.         this._clearTimeout();
  374.     },
  375.  
  376.  
  377.  
  378.     observe: function FGH_observe(aSubject, aTopic, aData) {
  379.         if (aTopic == "nsPref:changed")
  380.             this._reloadPrefs();
  381.     },
  382.  
  383.  
  384.  
  385.     _gestureTimer: null,
  386.  
  387.     _setTimeout: function FGH__setTimeout(aMsec) {
  388.         this._clearTimeout();
  389.         this._gestureTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  390.         this._gestureTimer.initWithCallback(this, aMsec, Ci.nsITimer.TYPE_ONE_SHOT);
  391.     },
  392.  
  393.     _clearTimeout: function FGH__clearTimeout() {
  394.         if (this._gestureTimer) {
  395.             this._gestureTimer.cancel();
  396.             this._gestureTimer = null;
  397.         }
  398.     },
  399.  
  400.     notify: function(aTimer) {
  401.         this._suppressContext = true;
  402.         this._shouldFireContext = false;
  403.         this._directionChain = "";
  404.         this._stopGesture();
  405.         this._gestureObserver.onExtraGesture(null, "gesture-timeout");
  406.     },
  407.  
  408.     openPopupAtPointer: function FGH_openPopupAtPointer(aPopup) {
  409.         aPopup.openPopupAtScreen(this._lastX, this._lastY, false);
  410.         this._directionChain = "";
  411.         this._stopGesture();
  412.     },
  413.  
  414.  
  415.  
  416.     _trailDot: null,
  417.     _trailArea: null,
  418.     _trailLastDot: null,
  419.     _trailOffsetX: 0,
  420.     _trailOffsetY: 0,
  421.     _trailZoom: 1,
  422.  
  423.     createTrail: function FGH_createTrail(event) {
  424.         var doc;
  425.         if (event.view.top.document instanceof Ci.nsIDOMHTMLDocument)
  426.             doc = event.view.top.document;
  427.         else if (event.view.document instanceof Ci.nsIDOMHTMLDocument)
  428.             doc = event.view.document;
  429.         else
  430.             return;
  431.         var insertionNode = doc.documentElement ? doc.documentElement : doc;
  432.         if (doc.getBoxObjectFor) {
  433.             var box = doc.getBoxObjectFor(insertionNode);
  434.             this._trailOffsetX = box.screenX;
  435.             this._trailOffsetY = box.screenY;
  436.             this._trailZoom = 1;
  437.             var tabbrowser = this._drawArea.ownerDocument.defaultView.gBrowser;
  438.             if (tabbrowser && (tabbrowser.mCurrentBrowser || tabbrowser).markupDocumentViewer.fullZoom != 1) {
  439.                 var dot = doc.createElementNS(HTML_NS, "xdTrailDot");
  440.                 dot.style.top = "1048576px";
  441.                 dot.style.position = "absolute";
  442.                 insertionNode.appendChild(dot);
  443.                 this._trailZoom = (doc.getBoxObjectFor(dot).screenY - this._trailOffsetY) / dot.offsetTop;
  444.                 insertionNode.removeChild(dot);
  445.             }
  446.         }
  447.         else {
  448.             var win = doc.defaultView;
  449.             this._trailZoom = win.QueryInterface(Ci.nsIInterfaceRequestor).
  450.                               getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
  451.             this._trailOffsetX = (win.mozInnerScreenX - win.scrollX) * this._trailZoom;
  452.             this._trailOffsetY = (win.mozInnerScreenY - win.scrollY) * this._trailZoom;
  453.         }
  454.         this._trailArea = doc.createElementNS(HTML_NS, "xdTrailArea");
  455.         insertionNode.appendChild(this._trailArea);
  456.         this._trailDot = doc.createElementNS(HTML_NS, "xdTrailDot");
  457.         this._trailDot.style.width = this._trailSize + "px";
  458.         this._trailDot.style.height = this._trailSize + "px";
  459.         this._trailDot.style.background = this._trailColor;
  460.         this._trailDot.style.border = "0px";
  461.         this._trailDot.style.position = "absolute";
  462.         this._trailDot.style.zIndex = 2147483647;
  463.     },
  464.  
  465.     drawTrail: function FGH_drawTrail(x1, y1, x2, y2) {
  466.         if (!this._trailArea)
  467.             return;
  468.         var xMove = x2 - x1;
  469.         var yMove = y2 - y1;
  470.         var xDecrement = xMove < 0 ? 1 : -1;
  471.         var yDecrement = yMove < 0 ? 1 : -1;
  472.         x2 -= this._trailOffsetX;
  473.         y2 -= this._trailOffsetY;
  474.         if (Math.abs(xMove) >= Math.abs(yMove))
  475.             for (var i = xMove; i != 0; i += xDecrement)
  476.                 this._strokeDot(x2 - i, y2 - Math.round(yMove * i / xMove));
  477.         else
  478.             for (var i = yMove; i != 0; i += yDecrement)
  479.                 this._strokeDot(x2 - Math.round(xMove * i / yMove), y2 - i);
  480.     },
  481.  
  482.     eraseTrail: function FGH_eraseTrail() {
  483.         if (this._trailArea && this._trailArea.parentNode) {
  484.             while (this._trailArea.lastChild)
  485.                 this._trailArea.removeChild(this._trailArea.lastChild);
  486.             this._trailArea.parentNode.removeChild(this._trailArea);
  487.         }
  488.         this._trailDot = null;
  489.         this._trailArea = null;
  490.         this._trailLastDot = null;
  491.     },
  492.  
  493.     _strokeDot: function FGH__strokeDot(x, y) {
  494.         if (this._trailArea.y == y && this._trailArea.h == this._trailSize) {
  495.             var newX = Math.min(this._trailArea.x, x);
  496.             var newW = Math.max(this._trailArea.x + this._trailArea.w, x + this._trailSize) - newX;
  497.             this._trailArea.x = newX;
  498.             this._trailArea.w = newW;
  499.             this._trailLastDot.style.left  = newX.toString() + "px";
  500.             this._trailLastDot.style.width = newW.toString() + "px";
  501.             return;
  502.         }
  503.         else if (this._trailArea.x == x && this._trailArea.w == this._trailSize) {
  504.             var newY = Math.min(this._trailArea.y, y);
  505.             var newH = Math.max(this._trailArea.y + this._trailArea.h, y + this._trailSize) - newY;
  506.             this._trailArea.y = newY;
  507.             this._trailArea.h = newH;
  508.             this._trailLastDot.style.top    = newY.toString() + "px";
  509.             this._trailLastDot.style.height = newH.toString() + "px";
  510.             return;
  511.         }
  512.         if (this._trailZoom != 1) {
  513.             x = Math.floor(x / this._trailZoom);
  514.             y = Math.floor(y / this._trailZoom);
  515.         }
  516.         var dot = this._trailDot.cloneNode(true);
  517.         dot.style.left = x + "px";
  518.         dot.style.top = y + "px";
  519.         this._trailArea.x = x;
  520.         this._trailArea.y = y;
  521.         this._trailArea.w = this._trailSize;
  522.         this._trailArea.h = this._trailSize;
  523.         this._trailArea.appendChild(dot);
  524.         this._trailLastDot = dot;
  525.     },
  526.  
  527. };
  528.  
  529.  
  530.  
  531. function NSGetModule(compMgr, fileSpec) {
  532.     return XPCOMUtils.generateModule([xdGestureHandler]);
  533. }
  534.  
  535.  
  536.